package com.xunk.equipment.service.mandun.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xunk.common.core.constant.HttpStatus;
import com.xunk.common.core.enums.DeviceEnum;
import com.xunk.common.core.text.Convert;
import com.xunk.common.core.utils.DataUtils;
import com.xunk.common.core.utils.HttpUtil;
import com.xunk.common.core.utils.XunkAssert;
import com.xunk.common.core.web.domain.AjaxResult;
import com.xunk.common.redis.service.RedisService;
import com.xunk.equipment.config.MandunConfig;
import com.xunk.equipment.domain.EquipmentDO;
import com.xunk.equipment.mapper.HomeMapper;
import com.xunk.equipment.service.BaseService;
import com.xunk.equipment.service.IAirSwitchService;
import com.xunk.equipment.service.mandun.constant.MandunConstant;
import com.xunk.equipment.service.mandun.service.IMandunService;
import com.xunk.equipment.service.mandun.util.MandunUtil;
import com.xunk.equipment.service.mandun.vo.IntervalRequest;
import com.xunk.equipment.service.mandun.vo.IntervalResponse;
import com.xunk.equipment.service.mandun.vo.MandunFacilityProperty;
import com.xunk.equipment.vo.response.AirSwitchResponse;
import com.xunk.equipment.websocket.WebsocketManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.xunk.common.core.domain.EquipmentResponse;

/**
 * @ProjectName: xunk
 * @Package: com.xunk.equipment.service.mandun.service.impl
 * @ClassName: MandunSwitchControlService
 * @Author: luanzhiwei
 * @Description: 曼顿设备开关控制
 * @Date: 2021/3/30 14:06
 * @Version: 1.0
 */
@Slf4j
@Service("mandun-airSwitch")
@RefreshScope
public class MandunAirSwitchServiceImpl implements IAirSwitchService {

    @Autowired
    private MandunConfig config;
    @Autowired
    private IMandunService mandunService;

    private static final BigDecimal THOUSAND = new BigDecimal("1000");

    @Value("#{'${equipment.fake:0}'.split(',')}")
    private List<String> FAKE_SWITCH_SET;

    @Autowired
    BaseService baseService;

    @Autowired
    RedisService redisService;

    @Autowired
    HomeMapper homeMapper;

    /**
     * 获取设备的开关状态，提供给用户端
     *
     * @param mac
     * @return
     */
    @Override
    public AjaxResult getSwitchStatus(String mac) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_GET_BOX_CHANNELS_OC, config.getAppKey(), mandunService.getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success(jsonObject.getJSONArray(MandunConstant.DATA));

    }


    /**
     * 设备控制接口
     * （此接口目前仅限于设备类型是微型断路器）
     * 目前只支持开关
     * cmd = OCSWITCH
     * addr 线路地址（多个线路地址请用逗号分隔）
     *
     * @param mac
     * @param control = open 打开开关，cmd=close关闭开关
     * @param addr
     * @return
     */
    @Override
    public AjaxResult changeSwitchStatus(String mac, String control, String addr) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_PUT_BOX_CONTROL, config.getAppKey(), mandunService.getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);
        request.put(MandunConstant.CMD, MandunConstant.OCSWITCH);
        request.put(MandunConstant.VALUE1, control);//开或关
        request.put(MandunConstant.VALUE2, addr);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success(MandunUtil.getMsg(jsonObject));
    }

    /**
     * 修改空开中具体某个空开的名称
     *
     * @param deviceSn 当前设备的唯一id
     * @param addr     当前设备（mac）下的某个空开的id
     * @param name
     * @return
     */
    @Override
    public AjaxResult renameSwitch(String deviceSn, String addr, String name) {
        TreeMap request = MandunUtil.getCommonRequest(MandunConstant.API_PUT_BOX_CONTROL, config.getAppKey(), mandunService.getToken());
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, deviceSn);
        request.put(MandunConstant.CMD, MandunConstant.SWITCHSET);
        request.put(MandunConstant.VALUE1, Long.valueOf(addr));//addr 线路地址 long
        request.put(MandunConstant.VALUE2, name);//线路名称
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map headers = new HashMap();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        if (!MandunUtil.isSuccess(jsonObject)) {
            return AjaxResult.error(MandunUtil.getMsg(jsonObject));
        }
        return AjaxResult.success();
    }


    @Override
    public EquipmentResponse getEquipmentInfo(EquipmentDO equipmentDO) {
        String deviceSn = equipmentDO.getDeviceSn();
        AjaxResult boxChannelsRealtime = mandunService.getBoxChannelsRealtime(deviceSn);
        Map<String, Object> data = Optional.ofNullable((Map<String, Object>) boxChannelsRealtime.getData()).orElseGet(HashMap::new);
        AirSwitchResponse response = new AirSwitchResponse();
        response.setDeviceSn(deviceSn);
        log.info("set {}  sn {}", JSON.toJSONString(FAKE_SWITCH_SET), deviceSn);
        if (FAKE_SWITCH_SET.contains(deviceSn)) {
            final AjaxResult month = mandunService.getInterval(new IntervalRequest(deviceSn, "month"));
            final List<IntervalResponse> monthData = (List<IntervalResponse>) month.getData();
            final BigDecimal electricity = monthData.stream().map(IntervalResponse::getElectricity).reduce(new BigDecimal("0"), BigDecimal::add);
            response.setElectricity(Convert.toStr(electricity.setScale(4, RoundingMode.HALF_DOWN)));
            final BigDecimal currentPower = monthData.stream().map(IntervalResponse::getCurrentPower).reduce(new BigDecimal("0"), BigDecimal::add);
            response.setCurrentPower(Convert.toStr(currentPower.setScale(2, RoundingMode.HALF_UP)));
        } else {
            response.setElectricity(Optional.ofNullable(data.get("electricity")).map(s -> (BigDecimal) s).map(s -> s.setScale(4, RoundingMode.HALF_DOWN).toString()).orElse(""));
            response.setCurrentPower(Optional.ofNullable(data.get("currentPower")).map(s -> (BigDecimal) s).map(s -> s.divide(THOUSAND, 2, RoundingMode.HALF_UP).toString()).orElse(""));
        }
        response.setUnit((List<Map<String, Object>>) data.get("list"));
        response.setOc(Optional.ofNullable(data.get("oc")).map(s -> (Boolean) s).orElse(false));
        response.setAddr(Optional.ofNullable(data.get("addr")).map(s -> (String) s).orElse(""));

        //  获取设备的硬件信息
        MandunFacilityProperty properties = mandunService.getBoxProperties(deviceSn);
        response.setModel(properties.getModel() == null ? "-" : properties.getModel());
        response.setFirmWare(properties.getVersion() == null ? "-" : properties.getVersion());
        response.setSerialNumber(properties.getImei() == null ? "-" : properties.getImei());
        response.setMac(properties.getMac() == null ? "-" : properties.getMac());
        response.setSupplier(equipmentDO.getSupplier());
        response.setCandidateModel(baseService.getCandidateModel(equipmentDO.getDeviceBaseId()));
        return response;
    }

    /**
     * 对于曼顿的设备
     * type:switch-1 代表线路1要更改开关的状态
     * value:0/1 0证明是关，需要翻译成close，1证明是开，翻译成open
     *
     * @param equipmentDO 当前设备信息，包含设备id，设备厂商
     * @param type        控制类型，如温度、开关、模式
     * @param value       操作目标值  如 20°(20)、open(true)、冷风模式(3)
     * @return
     */
    @Override
    public Boolean control(EquipmentDO equipmentDO, String type, String value) {
        String mac = equipmentDO.getDeviceSn();
        TreeMap<String, Object> request = MandunUtil.getCommonRequest(MandunConstant.API_PUT_BOX_CONTROL, config.getAppKey(), mandunService.getToken());
        String[] split = type.split("-");
        XunkAssert.isTrue(split.length == 2, "指令格式不正确");
        String cmd = split[0];
        String addr = split[1];
        String control = "";
        switch (cmd) {
            case "switch":
                cmd = MandunConstant.OCSWITCH;
                control = Objects.equals("1", value) ? "open" : "close";
                break;
            default:
                throw new RuntimeException("暂不支持开关之外的其他指令");
        }
        request.put(MandunConstant.PROJECT_CODE, config.getProjectCode());
        request.put(MandunConstant.MAC, mac);
        request.put(MandunConstant.CMD, cmd);
        request.put(MandunConstant.VALUE1, control);//开或关
        request.put(MandunConstant.VALUE2, addr);
        request.put(MandunConstant.SIGN, MandunUtil.sign(request, config.getAppSecret()));
        Map<String, Object> headers = new HashMap<>();
        headers.put(MandunConstant.CONTENT_TYPE, MandunConstant.CONTENT_TYPE_JSON);
        JSONObject jsonObject = HttpUtil.post(config.getUrlPrefix() + config.getRouterSuffix(), request, headers, JSONObject.class);
        return MandunUtil.isSuccess(jsonObject);
    }

    private Boolean fakeControl(EquipmentDO equipmentDO, String type, String value) {
        String[] split = type.split("-");
        XunkAssert.isTrue(split.length == 2, "指令格式不正确");
        Integer addr = Integer.valueOf(split[1]);
        String ancestor = baseService.findAncestorByDeptId(equipmentDO.getDeptId());
        String key = ancestor.concat(":").concat(equipmentDO.getDeviceSn());
        AirSwitchResponse airSwitchResponse = redisService.getCacheObject(key);
        List<Map<String, Object>> unitList = airSwitchResponse.getUnit();
        Map<String, Object> target = unitList.stream().filter(item -> Objects.equals(addr, item.get("addr"))).findFirst().get();
        target.put("oc", Objects.equals("1", value));
        if (Objects.equals(target.getOrDefault("mainLine", "0").toString(), "1")) {
            airSwitchResponse.setOc(Objects.equals("1", value));
        }
        redisService.setCacheObject(key, airSwitchResponse);

        // 发送websocket消息
        // 推送APP实时数据
        CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Map<String, Object> m = new HashMap<>();
            m.put("code", HttpStatus.SUCCESS);
            m.put("msg", "设备信息");
            // 设备控制类型 为3
            m.put("type", 3);
            Map<String, Object> unit = new HashMap<>();
            unit.put("online", target.get("online"));
            unit.put("mac", airSwitchResponse.getDeviceSn());
            unit.put("addr", target.get("addr"));
            unit.put("title", target.get("title"));
            unit.put("mainLine", target.get("mainLine"));

            Map<String, Object> properties = new HashMap<>();
            properties.put("oc", target.get("oc"));

            unit.put("deviceSn", airSwitchResponse.getDeviceSn());
            unit.put("properties", properties);
            unit.put("deviceType", DeviceEnum.AIR_SWITCH.getDeviceType());

            m.put("data", unit);

            List<Long> userIds = homeMapper.listUserIdsByDeptId(equipmentDO.getDeptId());
            String s = JSON.toJSONString(m);
            userIds.forEach(userId -> WebsocketManager.appointSending(String.valueOf(userId), s));
        });
        return true;
    }

    private EquipmentResponse fakeInfo(EquipmentDO equipmentDO) {
        String ancestor = baseService.findAncestorByDeptId(equipmentDO.getDeptId());
        String key = ancestor.concat(":").concat(equipmentDO.getDeviceSn());
        AirSwitchResponse airSwitchResponse = redisService.getCacheObject(key);
        if (DataUtils.isNotEmpty(airSwitchResponse)) {
            return airSwitchResponse;
        }
        airSwitchResponse = new AirSwitchResponse();
        airSwitchResponse.setCurrentPower("0.00");
        airSwitchResponse.setElectricity("0.0000");
        airSwitchResponse.setDeviceSn(equipmentDO.getDeviceSn());
        final AirSwitchResponse temp = airSwitchResponse;
        List<Map<String, Object>> unit = Stream.iterate(1, n -> n + 1).limit(7).map(n -> {
            Map<String, Object> m = new HashMap<>();
            m.put("oc", true);
            m.put("mainLine", n == 1 ? "1" : "0");
            if (n == 1) {
                temp.setOc(true);
                temp.setAddr("1");
            }
            m.put("online", true);
            m.put("addr", n + "");
            m.put("title", n == 1 ? "空开总闸" : ("线路" + (n - 1)));
            return m;
        }).collect(Collectors.toList());
        airSwitchResponse.setUnit(unit);
        airSwitchResponse.setModel("-");
        airSwitchResponse.setFirmWare("-");
        airSwitchResponse.setSerialNumber("-");
        airSwitchResponse.setMac("-");
        redisService.setCacheObject(key, airSwitchResponse);
        return airSwitchResponse;
    }

}
